﻿using System.Collections.Generic;
using System.Linq;
using FNN.Networks;
using FNN.Intervals;

namespace FNN.Genetic.Managers
{
    public class FinancialCrossbreedingManager : CrossbreedingManager
    {
        /// <summary>
        ///     Скрещивание на основе "качества" кандидатов
        /// </summary>
        /// <param name="sourceList">Исходный список кандидатов на скрещивание</param>
        /// <returns>Список детей</returns>
        public override List<Network> AdvancedSelection(List<Network> sourceList)
        {
            List<Network> result = new List<Network>();
            Dictionary<Network, Network> crossbreedingPairs = new Dictionary<Network, Network>();

            List<PossibilityInterval> intervals = new List<PossibilityInterval>();

            double lastValue = 0.0;
            double totalNetworkQuality = sourceList.Sum(o => ((FinancialNetwork)o).Funds);
            for (int i = 0; i < sourceList.Count; i++)
            {
                var currentPossibility = ((FinancialNetwork)sourceList.ElementAt(i)).Funds / totalNetworkQuality;
                intervals.Add(new PossibilityInterval(lastValue, lastValue + currentPossibility, sourceList.ElementAt(i)));
                lastValue += currentPossibility;
            }

            while (sourceList.Count > 0)
            {
                var randomValue = _randomizer.NextDouble();
                PossibilityInterval interval =
                    intervals.FirstOrDefault(o => (o.Start <= randomValue) && (o.End > randomValue));

                while (interval == null)
                {
                    randomValue = _randomizer.NextDouble();
                    interval =
                        intervals.FirstOrDefault(o => (o.Start <= randomValue) && (o.End > randomValue));
                }
                Network firstNetwork = interval.TargetNetwork;

                randomValue = _randomizer.NextDouble();
                interval =
                    intervals.FirstOrDefault(o => (o.Start <= randomValue) && (o.End > randomValue));

                while (interval == null)
                {
                    randomValue = _randomizer.NextDouble();
                    interval =
                        intervals.FirstOrDefault(o => (o.Start <= randomValue) && (o.End > randomValue));
                }
                Network secondNetwork = interval.TargetNetwork;

                while (secondNetwork == firstNetwork)
                {
                    randomValue = _randomizer.NextDouble();
                    interval =
                        intervals.FirstOrDefault(o => (o.Start <= randomValue) && (o.End > randomValue));

                    while (interval == null)
                    {
                        randomValue = _randomizer.NextDouble();
                        interval =
                            intervals.FirstOrDefault(o => (o.Start <= randomValue) && (o.End > randomValue));
                    }
                    secondNetwork = interval.TargetNetwork;
                }

                crossbreedingPairs.Add(firstNetwork, secondNetwork);
                sourceList.Remove(firstNetwork);
                sourceList.Remove(secondNetwork);
                intervals.RemoveAll(o => (o.TargetNetwork == firstNetwork) || (o.TargetNetwork == secondNetwork));
            }

            result = ExecuteCrossbreeding(crossbreedingPairs);

            return result;
        }


        /// <summary>
        ///     Запустить процесс скрещивания
        /// </summary>
        /// <param name="sourcePairs">Пары для скрещивания</param>
        /// <returns></returns>
        protected override List<Network> ExecuteCrossbreeding(Dictionary<Network, Network> sourcePairs)
        {
            List<Network> result = new List<Network>();
            foreach(var dominantNetwork in sourcePairs.Keys)
            {
                var recessiveNetwork = sourcePairs[dominantNetwork];
                DnaHelix dominantHelix = new DnaHelix();
                dominantHelix.ParseNetwork(dominantNetwork);
                DnaHelix recessiveHelix = new DnaHelix();
                recessiveHelix.ParseNetwork(recessiveNetwork);

                var currentCrossbreeding = new Crossbreeding();
                var resultHelix = currentCrossbreeding.Perform(dominantHelix, recessiveHelix);
                var newNetwork = new FinancialNetwork(resultHelix.GetNetworkStructure());
                result.Add(newNetwork);
            }
            return result;
        }
    }
}
